package com.gitee.wsl.func.transform.sample


import com.gitee.wsl.func.predicate.Predicate
import com.gitee.wsl.func.transform.Transformer
import com.gitee.wsl.func.transform.sample.NOPTransformer.Companion.nopTransformer

/**
 * Transformer implementation that will call one of two closures based on whether a predicate evaluates
 * as true or false.
 *
 * @param <T> the type of the input to the function.
 * @param <R> the type of the result of the function.
 * @since 4.1
</R></T> */
class IfTransformer<T, R>(
    /** The test  */
    val predicate: Predicate<in T>,
    trueTransformer: Transformer<in T, out R>,
    falseTransformer: Transformer<in T, out R>,
) : Transformer<T, R> {
    /**
     * Gets the predicate.
     *
     * @return the predicate
     */

    /** The transformer to use if true  */
    private val iTrueTransformer: Transformer<in T, out R> = trueTransformer

    /** The transformer to use if false  */
    private val iFalseTransformer: Transformer<in T, out R> = falseTransformer

    val falseTransformer: Transformer<in T, out R>
        /**
         * Gets the transformer used when false.
         *
         * @return the transformer
         */
        get() = iFalseTransformer

    val trueTransformer: Transformer<in T, out R>
        /**
         * Gets the transformer used when true.
         *
         * @return the transformer
         */
        get() = iTrueTransformer

    /**
     * Transforms the input using the true or false transformer based to the result of the predicate.
     *
     * @param input  the input object to transform
     * @return the transformed result
     */
    public override fun transform(input: T): R {
        if (predicate.test(input)) {
            return iTrueTransformer.apply(input)
        }
        return iFalseTransformer.apply(input)
    }

    companion object {

        /**
         * Factory method that performs validation.
         *
         * @param <I>  input type for the transformer
         * @param <O>  output type for the transformer
         * @param predicate  predicate to switch on
         * @param trueTransformer  transformer used if true
         * @param falseTransformer  transformer used if false
         * @return the `if` transformer
         * @throws NullPointerException if either argument is null
        </O></I> */
        fun <I, O> ifTransformer(
            predicate: Predicate<in I>,
            trueTransformer: Transformer<in I, out O>,
            falseTransformer: Transformer<in I, out O>,
        ): Transformer<I, O> {
            return IfTransformer(
                predicate,
                trueTransformer,
                falseTransformer
            )
        }

        /**
         * Factory method that performs validation.
         *
         *
         * This factory creates a transformer that just returns the input object when
         * the predicate is false.
         *
         * @param <T>  input and output type for the transformer
         * @param predicate  predicate to switch on
         * @param trueTransformer  transformer used if true
         * @return the `if` transformer
         * @throws NullPointerException if either argument is null
        </T> */
        fun <T> ifTransformer(
            predicate: Predicate<in T>,
            trueTransformer: Transformer<in T, out T>,
        ): Transformer<T, T> {
            return IfTransformer(
                predicate,
                trueTransformer,
                nopTransformer()
            )
        }
    }
}
